// PGLDataTypes.cpp: implementation of the CPGLDataTypes class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <pgl/core/PGLDataTypes.h>
#include <pgl/core/PGLDataVectors.h>
#include <pgl/core/DataRegistry.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#ifndef PGL_IMPLEMENT_VALARRAY_DATA_TYPE
#define PGL_IMPLEMENT_VALARRAY_DATA_TYPE( className )\
void className ::SerializeXML(CPGLArchive& ar) \
{ \
	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup()); \
	if(ar.IsStoring()) \
	{ \
		xml.AddChildElem(GetClassName()); \
		xml.IntoElem(); \
			xml.AddChildElemEx(_T("Values"), m_v); \
		xml.OutOfElem(); \
	} \
	else \
	{ \
		if  (!xml.FindChildElem(GetClassName())) \
				return; \
		xml.IntoElem(); \
			xml.FindGetChildData(_T("Values"), m_v); \
		xml.OutOfElem(); \
	} \
}
#endif

#ifndef PGL_IMPLEMENT_VAL_REF_DATA_TYPE
#define PGL_IMPLEMENT_VAL_REF_DATA_TYPE( className, replaceClassName )\
void className ::SerializeXML(CPGLArchive& ar) \
{ \
	replaceClassName dummy( GetV() ); \
	dummy.SerializeXML(ar); \
}
#endif

#ifndef PGL_IMPLEMENT_CIRCVECTOR_DATA_TYPE
#define PGL_IMPLEMENT_CIRCVECTOR_DATA_TYPE( className )\
void className ::SerializeXML(CPGLArchive& ar) \
{ \
	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup()); \
	if(ar.IsStoring()) \
	{ \
		xml.AddChildElem(GetClassName()); \
		xml.IntoElem(); \
			xml.AddChildElemEx(_T("Values"), m_v); \
			xml.AddChildElemEx(_T("Start"), m_uStart);\
		xml.OutOfElem(); \
	} \
	else \
	{ \
		if  (!xml.FindChildElem(GetClassName())) \
				return; \
		xml.IntoElem(); \
			xml.FindGetChildData(_T("Values"), m_v); \
			xml.FindGetChildData(_T("Start"), m_uStart);\
			m_uStart = __min( m_uStart, m_v.size()-1); \
		xml.OutOfElem(); \
	} \
}
#endif

PGL_REGISTER_DATA_TYPE( CPGLValarrayD );
PGL_REGISTER_DATA_TYPE( CPGLValarrayF );
PGL_REGISTER_DATA_TYPE( CPGLValarrayB );
PGL_REGISTER_DATA_TYPE( CPGLValarrayI );
PGL_REGISTER_DATA_TYPE( CPGLValarrayS );
PGL_REGISTER_DATA_TYPE( CPGLValarrayL );

PGL_IMPLEMENT_VALARRAY_DATA_TYPE( CPGLValarrayD );
PGL_IMPLEMENT_VALARRAY_DATA_TYPE( CPGLValarrayF );
PGL_IMPLEMENT_VALARRAY_DATA_TYPE( CPGLValarrayB );
PGL_IMPLEMENT_VALARRAY_DATA_TYPE( CPGLValarrayI );
PGL_IMPLEMENT_VALARRAY_DATA_TYPE( CPGLValarrayS );
PGL_IMPLEMENT_VALARRAY_DATA_TYPE( CPGLValarrayL );

PGL_REGISTER_DATA_TYPE( CPGLValarrayRefD );
PGL_REGISTER_DATA_TYPE( CPGLValarrayRefF );
PGL_REGISTER_DATA_TYPE( CPGLValarrayRefB );
PGL_REGISTER_DATA_TYPE( CPGLValarrayRefI );
PGL_REGISTER_DATA_TYPE( CPGLValarrayRefS );
PGL_REGISTER_DATA_TYPE( CPGLValarrayRefL );

PGL_IMPLEMENT_VAL_REF_DATA_TYPE( CPGLValarrayRefD, CPGLValarrayD );
PGL_IMPLEMENT_VAL_REF_DATA_TYPE( CPGLValarrayRefF, CPGLValarrayF );
PGL_IMPLEMENT_VAL_REF_DATA_TYPE( CPGLValarrayRefB, CPGLValarrayB );
PGL_IMPLEMENT_VAL_REF_DATA_TYPE( CPGLValarrayRefI, CPGLValarrayI );
PGL_IMPLEMENT_VAL_REF_DATA_TYPE( CPGLValarrayRefS, CPGLValarrayS );
PGL_IMPLEMENT_VAL_REF_DATA_TYPE( CPGLValarrayRefL, CPGLValarrayL );

PGL_REGISTER_DATA_TYPE( CPGLCircVectorD );
PGL_REGISTER_DATA_TYPE( CPGLCircVectorF );
PGL_REGISTER_DATA_TYPE( CPGLCircVectorB );
PGL_REGISTER_DATA_TYPE( CPGLCircVectorI );
PGL_REGISTER_DATA_TYPE( CPGLCircVectorS );
PGL_REGISTER_DATA_TYPE( CPGLCircVectorL );

PGL_IMPLEMENT_CIRCVECTOR_DATA_TYPE( CPGLCircVectorD );
PGL_IMPLEMENT_CIRCVECTOR_DATA_TYPE( CPGLCircVectorF );
PGL_IMPLEMENT_CIRCVECTOR_DATA_TYPE( CPGLCircVectorB );
PGL_IMPLEMENT_CIRCVECTOR_DATA_TYPE( CPGLCircVectorI );
PGL_IMPLEMENT_CIRCVECTOR_DATA_TYPE( CPGLCircVectorS );
PGL_IMPLEMENT_CIRCVECTOR_DATA_TYPE( CPGLCircVectorL );

#ifdef _MFC_7_MSCP1_2844
#if _MFC_VER >= 1300
//////////////////////////////////////////////////////////////////////////////:
// Tweak for bug 2844
namespace pgl
{
	namespace implement
	{
		template <typename T, class VT>
		void ImplementValarray()
		{
			size_t n=5;
			T t=1;
			T ar[2]={0, 1};
			float f=0;

			VT v;
			VT v2(n);
			const VT v3(v2);
			VT v4=v2;

			const VT::ValarrayT& vv=v2.GetV();
			VT::ValarrayT& vv2=v2.GetV();
			v4.SetV(vv);

			v2.size();
			v4.clear();
			v2.resize(5);

			v2[0]=t;
			v2.at(1)=t;
			f=v3[0];
			f=v3.at(0);
		}

		template <typename T, class VT>
		void ImplementValarrayRef()
		{
			size_t n=5;
			T t=1;
			T ar[2]={0, 1};
			float f=0;
			VT::ValarrayT vt(5);

			VT v;
			VT v2(vt);
			const VT v3(v2);
			VT v4=v2;
			VT v5(&vt);

			const VT::ValarrayT& vv=v2.GetV();
			v4.SetV(vv);

			v2.size();

			f=v3[0];
			f=v3.at(0);
		}

		template <typename T, class VT>
		void ImplementCircVector()
		{
			size_t i,n=5;
			T t=1;
			T ar[2]={0, 1};
			float f=0;

			VT v;
			VT v2(n);
			const VT v3(v2);
			VT v4=v2;

			const VT::VectorT& vv=v2.GetV();
			VT::VectorT& vv2=v2.GetV();
			v4.SetV(vv);

			v2.size();
			v4.clear();
			v2.resize(5);

			v2[0]=t;
			v2.at(1)=t;
			f=v3[0];
			f=v3.at(0);

			v2.StepStart();
			i=v2.GetStart();
			v2.SetStart(i);
		}		

		class CImplementCircValRefs
		{
		public:
			CImplementCircValRefs()
			{
				ImplementCircVector<float, CPGLCircVectorF>();
				ImplementCircVector<double, CPGLCircVectorD>();
				ImplementCircVector<int, CPGLCircVectorI>();
				ImplementCircVector<BYTE, CPGLCircVectorB>();
				ImplementCircVector<short, CPGLCircVectorS>();
				ImplementCircVector<long, CPGLCircVectorL>();

				ImplementValarray<float, CPGLValarrayF>();
				ImplementValarray<double, CPGLValarrayD>();
				ImplementValarray<int, CPGLValarrayI>();
				ImplementValarray<BYTE, CPGLValarrayB>();
				ImplementValarray<short, CPGLValarrayS>();
				ImplementValarray<long, CPGLValarrayL>();

				ImplementValarrayRef<float, CPGLValarrayRefF>();
				ImplementValarrayRef<double, CPGLValarrayRefD>();
				ImplementValarrayRef<int, CPGLValarrayRefI>();
				ImplementValarrayRef<BYTE, CPGLValarrayRefB>();
				ImplementValarrayRef<short, CPGLValarrayRefS>();
				ImplementValarrayRef<long, CPGLValarrayRefL>();
			}
		};

		static CImplementCircValRefs staticImplCircValRef;
	}
}
#endif
#endif

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CPGLLinearVector

CPGLLinearVector::CPGLLinearVector( float fOrigin, float fStep, size_t uNSteps )
: m_fOrigin(fOrigin), m_fStep(fStep), m_uNSteps(uNSteps)
{
};

CPGLLinearVector& CPGLLinearVector::operator = (const CPGLLinearVector& lv)
{
	if (this != &lv)
	{
		m_fOrigin=lv.m_fOrigin;
		m_fStep = lv.m_fStep;
		m_uNSteps = lv.m_uNSteps;
	}
	return *this;
}

void CPGLLinearVector::SerializeXML(CPGLArchive& ar)
{
	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());
	if(ar.IsStoring())
	{ 
		xml.AddChildElem(GetClassName()); 
		xml.IntoElem(); 
			xml.AddChildElemEx(_T("Origin"), m_fOrigin); 
			xml.AddChildElemEx(_T("Step"), m_fStep); 
			xml.AddChildElemEx(_T("Size"), m_uNSteps);
		xml.OutOfElem(); 
	} 
	else 
	{ 
		if  (!xml.FindChildElem(GetClassName())) 
				return; 
		xml.IntoElem(); 
			xml.FindGetChildData(_T("Origin"), m_fOrigin); 
			xml.FindGetChildData(_T("Step"), m_fStep); 
			xml.FindGetChildData(_T("Size"),m_uNSteps);
		xml.OutOfElem(); 
	} 
}

PGL_REGISTER_DATA_TYPE( CPGLLinearVector );

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CPGLFcnData

CPGLFcnData& CPGLFcnData::operator = (const CPGLFcnData& lv)
{
	if (this != & lv)
	{
		m_pData.reset();

		if (lv.m_pData)
			m_pData = lv.m_pData;

		m_pFcn = lv.m_pFcn;
	}

	return *this;
}

void CPGLFcnData::GetFx(std::vector<float>& v)
{
	if (!m_pData || !m_pFcn)
		return;
/*
	v.resize( m_pData->size());
	for (size_t i=0;i<m_pData->size();i++)
		v[i]=m_pFcn((*m_pData)[i]);
*/
}

void CPGLFcnData::SerializeXML(CPGLArchive& ar)
{
	if (!m_pData || !m_pFcn)
		return;

	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());

	if(ar.IsStoring())
	{ 
//		CPGLValarrayF dummy;
//		GetFx(dummy.GetV());
//		dummy.SerializeXML(ar);
	} 
	else 
	{ 
		ASSERT(FALSE);
	} 
}

PGL_REGISTER_DATA_TYPE( CPGLFcnData );

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CPGLMathFcnData
CPGLMathFcnData& CPGLMathFcnData::operator = (const CPGLMathFcnData& lv)
{
	if (this != & lv)
	{
		m_pData.reset();

		if (lv.m_pData)
			m_pData = lv.m_pData;

		m_parser = lv.m_parser;
	}

	return *this;
}

float CPGLMathFcnData::at(size_t i) const				
{	
	ASSERT(m_pData.get()); 
		
	double val=m_pData->at(i); 	

	try
	{
		return static_cast<float>(m_parser.Eval( &val ));
	}
	catch (LPCTSTR szError)
	{
		PGL_TRACE1(_T("Function parser error: %s\n"), szError);
		return 0;
	}
};

LPCTSTR CPGLMathFcnData::GetParseErrorMsg() const
{	
	return m_parser.GetParseErrorMsg();
};

int CPGLMathFcnData::Parse( LPCTSTR szFunction, LPCTSTR szVar)
{	
	return m_parser.Parse(szFunction, szVar);
};

void CPGLMathFcnData::GetFx(std::vector<float>& v)
{
	if (!m_pData)
		return;

	v.resize( m_pData->size());
	double val;
	for (size_t i=0;i<m_pData->size();i++)
	{
		val=(*m_pData)[i];
		v[i]=static_cast<float>(m_parser.Eval( &val ));
	}
}

void CPGLMathFcnData::SerializeXML(CPGLArchive& ar)
{
	CString strPos, sFunction, sVars;

	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());

	if(ar.IsStoring())
	{ 
		if (!m_pData)
		{
			xml.AddChildElemEx(_T("Data"));
			xml.IntoElem();
				m_pData->SerializeXML(ar);
			xml.OutOfElem();
		}
		xml.AddChildElemEx(_T("Fcn"));
		xml.IntoElem();
			xml.AddChildElemEx(_T("Function"), m_parser.GetFunction());
			xml.AddChildElemEx(_T("Vars"), m_parser.GetVars());
		xml.OutOfElem();
	} 
	else 
	{ 
		PGL_SERIALIZE_LOAD_DATA(strPos, Data, m_pData);
		if (xml.FindChildElem(_T("Fcn")))
		{
			xml.IntoElem();
				xml.FindGetChildData(_T("Function"), sFunction);
				xml.FindGetChildData(_T("Vars"), sVars);

				m_parser.Parse(sFunction, sVars);
			xml.OutOfElem();
		}
	} 
}

PGL_REGISTER_DATA_TYPE( CPGLMathFcnData );


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CPGLVectorPairRef
SAFEARRAY* CPGLSafeArray::AttachArray( SAFEARRAY* pArray, bool bCleaning )
{
	m_hr=S_FALSE;
	m_bCleaning = bCleaning;

	// preparing old array
	SAFEARRAY* pOldArray=NULL;
	if(m_bCleaning)
		CleanArray();
	else
	{
		pOldArray=m_pArray;
		m_pArray=NULL;
	}

	if (!pArray)
		goto End;

	// check array type...
	m_hr = SafeArrayGetVartype( pArray, &m_vt);	
	if (FAILED(m_hr))
		goto End;

	if ( m_vt != VT_I2 && m_vt!=VT_I4 && m_vt!=VT_R4 && m_vt!=VT_R8)
		goto End;

	// checking array dim
	if (SafeArrayGetDim( pArray ) != 1)
		goto End;

	m_pArray = pArray;		
	m_hr=S_OK;

End:
	return pOldArray;
}

SAFEARRAY* CPGLSafeArray::AttachArray( VARIANT v, bool bCleaning)
{
	// checking type...
	bool typeOK=false;
	switch(v.vt)
	{
	case VT_ARRAY | VT_R4:
	case VT_ARRAY | VT_R8:
	case VT_ARRAY | VT_I2:
	case VT_ARRAY | VT_I4:
		typeOK=true;
	}

	if (typeOK)
		return AttachArray( v.parray, bCleaning);
	else
		return NULL;
}

HRESULT CPGLSafeArray::CleanArray()
{
	if (!m_bCleaning || !m_pArray)
		return m_hr=S_OK;

	return m_hr=SafeArrayDestroy(m_pArray);
}

CPGLSafeArray::CPGLSafeArray(size_t n, VARTYPE vt)
:m_bCleaning(true), m_hr(S_OK), m_pArray(NULL)
{
	if (n<=0)
	{
		m_pArray=NULL;
		return;
	}

	m_vt=vt;
	if ( m_vt != VT_I2 && m_vt!=VT_I4 && m_vt!=VT_R4 && m_vt!=VT_R8)
		return;

	m_pArray=SafeArrayCreateVector(m_vt,0,n);
	if (m_pArray==NULL)
		m_hr=E_OUTOFMEMORY;
};
	
CPGLSafeArray::CPGLSafeArray( SAFEARRAY* pArray, bool bCleaning)
:m_bCleaning(false), m_hr(S_OK), m_pArray(NULL)
{
	AttachArray( pArray, bCleaning);
}

CPGLSafeArray::CPGLSafeArray( VARIANT v, bool bCleaning)
: m_bCleaning(false), m_hr(S_OK), m_pArray(NULL)
{
	AttachArray( v, bCleaning);
};


CPGLSafeArray& CPGLSafeArray::operator = (const CPGLSafeArray& sa)
{
	if (&sa!=this)
	{
		CleanArray();
		m_pArray = sa.m_pArray;
		m_bCleaning = false;
		m_hr = S_OK;
		m_vt=sa.m_vt;
	}

	return *this;
};

CPGLSafeArray::~CPGLSafeArray()
{
	CleanArray();
};
	
size_t CPGLSafeArray::size() const
{
	if (!m_pArray)
		return 0;

	long lUbound=0;
	SafeArrayGetUBound(m_pArray,1,&lUbound);
	return lUbound;
}

float CPGLSafeArray::at(size_t i) const
{
	if(!m_pArray)
		return 0;

	long rgIndices=i;
	long lt;
	int it;
	double dt;
	float ft;
	HRESULT hr;

	switch(m_vt)
	{
	case VT_I2:
		hr=SafeArrayGetElement( m_pArray,  &rgIndices, &it);
		if (FAILED(hr))
			return 0;
		else 
			return static_cast<float>(it);
	case VT_I4:
		hr=SafeArrayGetElement( m_pArray,  &rgIndices, &lt);
		if (FAILED(hr))
			return 0;
		else 
			return static_cast<float>(lt);
	case VT_R4:
		hr=SafeArrayGetElement( m_pArray,  &rgIndices, &ft);
		if (FAILED(hr))
			return 0;
		else 
			return ft;
	case VT_R8:
		hr=SafeArrayGetElement( m_pArray,  &rgIndices, &dt);
		if (FAILED(hr))
			return 0;
		else 
			return static_cast<float>(dt);
	default:
		return 0;
	}
}


void CPGLSafeArray::SerializeXML(CPGLArchive& ar)
{
	CString strPos, sFunction, sVars;

	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());

	if(ar.IsStoring())
	{ 
		CPGLVectorF vX( size() );
		CPGLVectorF::VectorT& v=vX.GetV();
		for (size_t i=0; i<v.size();++i)
			v[i]=at(i);

		vX.SerializeXML(ar);
	} 
	else 
	{ 
	} 
}

PGL_REGISTER_DATA_TYPE( CPGLSafeArray );
